I2C Physical Protocol
I2C Device Addressing
Procedure for writing time and date
Procedure for reading the time and date
Applications
/* Name : main.c * Purpose : Source code for RTC Interfacing with PIC18F4550. * Author : Gemicates * Date : 2017-06-14 * Website : www.gemicates.org * Revision : None */ #include <xc.h> // Header file for PIC18F4550 #define _XTAL_FREQ 12000000 // 12MHZ /****Configuration bits****/ #pragma config PLLDIV = 5 // PLL Prescaler Selection bits(20 MHz crystal on PICDEM FS USB board) #pragma config CPUDIV = OSC1_PLL2 // System Clock Postscaler Selection bits #pragma config USBDIV = 2 // USB Clock Selection bit,Clock source from 96MHz PLL/2 #pragma config FOSC = HSPLL_HS // Oscillator Frequency Range #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit #pragma config IESO = OFF // Oscillator Switchover mode disabled #pragma config PWRT = OFF // PWRT enabled #pragma config BOR = ON // Brown out reset #pragma config BORV = 3 // Brown-out Reset Voltage bits #pragma config VREGEN = ON // USB Voltage Regulator #pragma config WDT = OFF // Watchdog Timer Enable bit(WDT disabled) //#pragma config WDTPS = 32768 #pragma config MCLRE = ON // MCLR Pin Enable bit(MCLR pin enabled) #pragma config LPT1OSC = OFF // Low-Power Timer1 Oscillator Enable bit(Timer1 configured for higher power operation) #pragma config PBADEN = OFF // PORTB A/D Enable bit( pins are configured as digital I/O on Reset) #pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit(Stack full/underflow will cause Reset) #pragma config LVP = OFF // Single-Supply ICSP disabled #pragma config XINST = OFF // Extended Instruction Set /**********LCD Pin Configuration**********/ #define LCD_DATA_PINS PORTD // To assign LCD data pins PORTD #define RS PORTCbits.RC1 // To assign single pin(RC1) as output #define RW PORTCbits.RC0 // To assign single pin(RC0) as output #define EN PORTCbits.RC2 // To assign single pin(RC2) as output /*****************************************/ /**********Function Prototypes**********/ void LCD_Init(void); void LCD_Cmd(unsigned char); void LCD_Data(unsigned char value); void LCD_Str(const unsigned char *); void USART_Init(void); void USART_Write(unsigned char); void USART_Write_Str(const unsigned char *); void USART_Write_Str_Line(const unsigned char *); void USART_Write_Int(int ,unsigned char); unsigned char USARTReadByte(); void I2C_Init(void); void I2C_Start(void); void I2C_Restart(void); void I2C_Stop(void); void I2C_Wait(void); void I2C_Send(unsigned char dat); unsigned char I2C_Read(void); unsigned char rtc1307_read(unsigned char address); unsigned char BCD2UpperCh(unsigned char bcd); unsigned char BCD2LowerCh(unsigned char bcd); /************************************/ unsigned char sec,min,hour,date,month,year; const unsigned char time[] = "TIME:"; const unsigned char date_format[] = "DATE:"; const unsigned char rtc[] = "RTC DS1307"; void main() { TRISC = 0x80; //Reception Pin as Input Pin, rest all as output Pin TRISD = 0x00; //PORTD as output LCD_Init(); //Initialize LCD Module USART_Init(); //Initialize USART at 9600 BPS LCD_Cmd(0x84); //first line fourth character LCD_Str(rtc); //display rtc __delay_ms(10); I2C_Init(); //Initialize I2C __delay_ms(10); I2C_Start(); //Start the I2C protocol I2C_Send(0xD0); //7-bit DS1307 address I2C_Send(0x00); I2C_Send(0x80); //CH = 1 Stop oscillator I2C_Send(0x00); //Minute I2C_Send(0x06); //Hour I2C_Send(0x02); //Sunday I2C_Send(0x28); // 28 APRIL I2C_Send(0x04); // 4 April I2C_Send(0x95); // 1995 I2C_Stop(); //Stop the I2C Protocol __delay_ms(10); I2C_Start(); //Have to start the Clock again I2C_Send(0xD0); //7-bit DS1307 address I2C_Send(0x00); //7 bit address start I2C_Send(0x00); //start Clock and set the second hand to Zero I2C_Stop(); __delay_ms(10); LCD_Cmd(0x01); //Clear display screen while(1) //Infinite Loop For Reading Time and Date { sec = rtc1307_read(0x00); //Seconds address min = rtc1307_read(0x01); //min address hour = rtc1307_read(0x02); //hour address date = rtc1307_read(0x04); //date address month = rtc1307_read(0x05); //month address year = rtc1307_read(0x06); //year address __delay_ms(1); //delay of 1ms LCD_Cmd(0x80); //Cursor to beginning of 1st row LCD_Str(time); //To display the time LCD_Data(BCD2UpperCh(hour)); //BCD format to Upper Clock halt bit(hour) LCD_Data(BCD2LowerCh(hour)); //BCD format to Lower Clock halt bit(hour) LCD_Data(':'); //To display ':' LCD_Data(BCD2UpperCh(min)); //BCD format to Upper Clock halt bit(min) LCD_Data(BCD2LowerCh(min)); //BCD format to Lower Clock halt bit(min) LCD_Data(':'); //To display ':' LCD_Data(BCD2UpperCh(sec)); //BCD format to Upper Clock halt bit(sec) LCD_Data(BCD2LowerCh(sec)); //BCD format to Lower Clock halt bit(sec) LCD_Cmd(0xC0); //Cursor to beginning of 2nd row LCD_Str(date_format); //To display the date LCD_Data(BCD2UpperCh(date)); //BCD format to Upper Clock halt bit(date) LCD_Data(BCD2LowerCh(date)); //BCD format to Lower Clock halt bit(date) LCD_Data('/'); //To display '/' LCD_Data(BCD2UpperCh(month)); //BCD format to Upper Clock halt bit(month) LCD_Data(BCD2LowerCh(month)); //BCD format to Lower Clock halt bit(month) LCD_Data('/'); //To display '/' LCD_Data(BCD2UpperCh(year)); //BCD format to Upper Clock halt bit(year) LCD_Data(BCD2LowerCh(year)); //BCD format to Lower Clock halt bit(year) __delay_ms(10); //delay of 10ms } } /**********************************************/ /****************RTC FUNCTIONS*****************/ unsigned char BCD2UpperCh(unsigned char bcd) { unsigned char temp; temp = bcd >> 4; temp = temp | 0x30; //Lower 3-bits return(temp); } unsigned char BCD2LowerCh(unsigned char bcd) { unsigned char temp; temp = bcd & 0x0F; //Making the Upper 4-bits temp = temp | 0x30; return(temp); } unsigned char rtc1307_read(unsigned char address) { unsigned char temp; I2C_Start(); I2C_Send(0xD0); I2C_Send(address); //I2C function I2C_Restart(); I2C_Send(0xD1); temp = I2C_Read(); I2C_Stop(); return temp; } /**********************************************/ /*****************LCD FUNCTIONS****************/ void LCD_Init() { EN = 0; //Enable function __delay_ms(1); //delay of 1ms LCD_Cmd(0x38); //function set:8 bit,2nd line,5x7 dots __delay_ms(1); //delay of 1ms LCD_Cmd(0x0E); //Display On,Cursor On __delay_ms(1); //delay of 1ms LCD_Cmd(0x0C); //Display On Cursor Off __delay_ms(1); //delay of 1ms LCD_Cmd(0x01); //Clear display screen __delay_ms(1); //delay of 1ms LCD_Cmd(0x06); //Entry mode __delay_ms(1); //delay of 1ms LCD_Cmd(0x80); //Cursor to beginning of 1st row __delay_ms(1); //delay of 1ms } void LCD_Cmd(unsigned char value) //LCD command function { LCD_DATA_PINS = value; //LCD data pins PORTD RS = 0; //Register select(command mode) RW = 0; //Read/Writ(Write operation) EN = 1; //Enable pin __delay_ms(1); //delay of 1ms EN = 0; //Disable pin } void LCD_Data(unsigned char value) //LCD data function { LCD_DATA_PINS = value; //LCD data pins PORTD RS = 1; //Register select(Data mode) RW = 0; //Read/Write(Write operation) EN = 1; //Enable pin __delay_ms(1); //delay of 1ms EN = 0; //Disable pin } void LCD_Str(const unsigned char *str) //LCD string { while((*str)!='\0') { LCD_Data(*(str)); str++; //Increment the Pointer } } void USART_Init(void) // Serial Port UART { SPBRG = 77; //Baud Rate = 9600 Bits per Second TXSTAbits.TXEN=1; //Enable Transmission by setting these Value's TXSTAbits.BRGH=0; //BAUDRATE is low RCSTAbits.SPEN=1; //Enable Reception by Setting these Value's RCSTAbits.CREN=1; //Enable Receiver (RX) //BAUDCON BAUDCONbits.BRG16=0; } void USART_Write(unsigned char value) { while(PIR1bits.TXIF == 0); //Wait for TXREG Buffer to become available TXREG = value; //Transmitter register } void USART_Write_Str(const unsigned char *str) { while((*str)!='\0') { while(PIR1bits.TXIF == 0); //Wait for TXREG Buffer to become available TXREG = *(str); //Write Data str++; //Increment the Pointer } } void USART_Write_Str_Line(const unsigned char *str) { USART_Write_Str(str); //USART_Write_Str("\r\n"); //Formely I used to write this USART_Write(10); USART_Write(13); } void USART_Write_Int(int val,unsigned char field_length) { char str[5]={0,0,0,0,0}; int i=4,j=0; if(val<0) { USART_Write('-'); //Write '-' sign for negative numbers. val=(val*(-1)); //Make it positive. } while(val) //Convert Number To String and pump over Tx Channel. { str[i]=val%10; val=val/10; i--; } if(field_length>5) while(str[j]==0) j++; else j=5-field_length; for(i=j;i<5;i++) { USART_Write('0'+str[i]); } } unsigned char USARTReadByte() { while(!PIR1bits.RCIF); // EUSART Receive Interrupt Flag bit(Wait for a byte) return RCREG; //EUSART Receive Register } void I2C_Init() { TRISB |= 0x03; //PORTB as SDA and SCL enable pin SSPSTAT |= 0x80; // MSSP STATUS REGISTER (SPI MODE) Slew Rate Disabled SSPADD = 119; //MSSP Address Register (SSPADD) SSPCON1 = 0b00101000; //Master mode SSPADD = 119; //MSSP Address Register (SSPADD) /*SSPEN = 1 Enables the Serial Port and configures the SDA and SCL Pins as the Serial Pins SSPM3:SSPM0 --> 1000 I2C Master Mode Clock = Fosc/4*(SSPADD+1) */ } void I2C_Start(void) { SSPCON2bits.SEN = 1; //Start Condition Enable/Stretch Enable bit //SSPCON2 bit 0 while (SSPCON2bits.SEN == 1) //SEN =1 initiate the Start Condition on SDA and SCL Pins continue; } void I2C_Restart(void) { SSPCON2bits.RSEN = 1; //SSPCON2 bit 1 while (SSPCON2bits.RSEN == 1) //RSEN = 1 initiate the Restart Condition continue; //Automatically Cleared by Hardware } void I2C_Stop(void) { SSPCON2bits.PEN=1; // Initiate Stop condition on SDA and SCL pins. while(SSPCON2bits.PEN==1) //Automatically cleared by hardware. continue; } void I2C_Wait(void) { while(SSPSTATbits.R_NOT_W == 1) continue; if(SSPCON2bits.ACKSTAT == 1) //If ACKSTAT bit is 0 Acknowledgment Received Successfully { I2C_Stop(); } //Otherwise Not } void I2C_Send(unsigned char dat) { SSPBUF = dat; // Move data to SSPBUF */ while(SSPSTATbits.BF); // wait till complete data is sent from buffer */ I2C_Wait(); // wait for any pending transfer */ } unsigned char I2C_Read(void) { unsigned char temp; SSPCON2bits.RCEN = 1; // Enable data reception while(SSPSTATbits.BF == 0) // wait for buffer full continue; temp = SSPBUF; // Read serial buffer and store in temp register I2C_Wait(); // wait to check any pending transfer SSPCON2bits.ACKDT=1; //send not acknowledge SSPCON2bits.ACKEN=1; while(SSPCON2bits.ACKEN == 1) continue; //I2C_Stop(); return temp; //return the read data from bus */ }